#pragma once
#include <cmath>
#include "Dashun.h"

/* FIXME: 设置为每层可调节的 */
constexpr float LEAKY_RELU_ALPHA = 0.01;

/* 神经网络层接口 */
class ILayer {
public:

    /* 激活函数枚举类 */
    enum class ActivationFunc {
        None, ReLU, Leaky_ReLU, Sigmoid, Tanh
    };

protected:
    /* ReLU 激活函数 */
    static float relu(float x) {
        return (x > 0.0) ? x : 0.0;
    }
    /* ReLU 导数 */
    static float relu_derivative(float x) {
        return (x > 0) ? 1: 0;
    }
    /*
     * leaky ReLU 激活函数
     *
     * NOTE: alpha太小或者选择使用ReLU函数的情况下，会导致梯度消失 
     * NOTE: Leaky ReLU 不会使梯度完全消失，但也会使它变得很小
     */
    static float leaky_relu(float x) {
        return (x > 0) ? x : LEAKY_RELU_ALPHA * x;
    }
    /* leaky ReLU 导数 */
    static float leaky_relu_derivative(float x) {
        return (x > 0) ? 1.0f : LEAKY_RELU_ALPHA;
    }
    /* Sigmoid 激活函数 */
    static float sigmoid(float x) {
        return 1.0 / (1.0 + std::exp(-x));
    }
    /* Sigmoid 导数 */
    static float sigmoid_derivative(float x) {
        double s = sigmoid(x);
        return s * (1.0 - s);
    }
    /* Tanh 激活函数 */
    static float tanh(float x) {
        return std::tanh(x);
    }
    /* Tanh 导数 */
    static float tanh_derivative(float x) {
        return 1.0f - x * x;
    }
};